"""
绩效分析页面渲染模块。
"""
import streamlit as st
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
import datetime

# 从 app_setup 导入 logger
try:
    from .app_setup import logger
except ImportError:
    import logging
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)

# 默认行业和风格归因数据
DEFAULT_SECTOR_ATTRIBUTION = {"科技": 2.5, "消费": 1.8, "医疗": -0.5, "金融": 0.8, "能源": -0.3, "材料": 0.6}
DEFAULT_STYLE_ATTRIBUTION = {"大盘价值": 1.2, "大盘成长": 2.8, "中盘价值": 0.5, "中盘成长": 1.5, "小盘价值": -0.2, "小盘成长": -0.5}
DEFAULT_RISK_BREAKDOWN = {"系统性风险": 65, "行业风险": 20, "个股风险": 15}
DEFAULT_RISK_METRICS = {"波动率(年化)": 15.8, "Beta系数": 0.95, "下行风险": 8.5, "跟踪误差": 4.2, "VaR(95%)": 2.1, "信息比率": 1.25}

def render_performance():
    """渲染绩效分析界面"""
    st.markdown('<div class="main-header">绩效分析</div>', unsafe_allow_html=True)

    # --- 收益曲线 ---
    render_return_curve()

    # --- 关键绩效指标 ---
    render_kpis()

    # --- 月度收益表现 ---
    render_monthly_returns()

    # --- 归因分析 ---
    render_attribution_analysis()

    # --- 风险分析 ---
    render_risk_analysis()


def render_return_curve():
    """渲染收益曲线图"""
    st.markdown('<div class="sub-header">收益曲线</div>', unsafe_allow_html=True)

    time_range = st.select_slider(
        "选择时间范围",
        options=["1周", "1个月", "3个月", "6个月", "1年", "全部"],
        value="1个月" # 默认值
    )

    days_map = {"1周": 7, "1个月": 30, "3个月": 90, "6个月": 180, "1年": 365, "全部": 1000} # "全部" 增加天数
    selected_days = days_map[time_range]

    dates = pd.date_range(end=datetime.datetime.now(), periods=selected_days).strftime("%Y-%m-%d").tolist()
    cumulative_returns = np.zeros(selected_days)
    benchmark_cumulative_returns = np.zeros(selected_days)
    benchmark_name = "模拟基准" # 默认基准名称

    # 尝试使用真实数据或模拟生成
    try:
        if st.session_state.get('data_loaded', False) and 'indices_data' in st.session_state:
            # 优先使用沪深300，其次上证指数作为基准
            benchmark_data = st.session_state.indices_data.get("沪深300")
            benchmark_name = "沪深300"
            if benchmark_data is None or benchmark_data.empty:
                benchmark_data = st.session_state.indices_data.get("上证指数")
                benchmark_name = "上证指数"

            if benchmark_data is not None and not benchmark_data.empty:
                benchmark_data = benchmark_data.sort_values(by="date")
                # 确保日期列是 datetime 类型
                if not pd.api.types.is_datetime64_any_dtype(benchmark_data['date']):
                    benchmark_data['date'] = pd.to_datetime(benchmark_data['date'])

                # 选择对应时间范围的数据
                end_date = benchmark_data['date'].max()
                start_date = end_date - pd.Timedelta(days=selected_days * 1.5) # 多取一些数据以防工作日不够
                recent_benchmark = benchmark_data[benchmark_data['date'] >= start_date].tail(selected_days)


                if len(recent_benchmark) >= 2:
                    benchmark_prices = recent_benchmark['close'].values
                    # 计算每日收益率，处理 NaN 和零值
                    valid_prices = benchmark_prices[pd.notna(benchmark_prices)]
                    if len(valid_prices) >= 2:
                        # 使用 pct_change 更安全
                        benchmark_daily_returns = recent_benchmark['close'].pct_change().fillna(0).values
                        # 确保长度匹配 selected_days
                        if len(benchmark_daily_returns) < selected_days:
                             benchmark_daily_returns = np.pad(benchmark_daily_returns, (selected_days - len(benchmark_daily_returns), 0), 'constant')
                        elif len(benchmark_daily_returns) > selected_days:
                             benchmark_daily_returns = benchmark_daily_returns[-selected_days:]

                        benchmark_cumulative_returns = (1 + benchmark_daily_returns).cumprod() - 1

                        # 模拟组合收益率 (基于基准 + 随机性 + 轻微超额)
                        np.random.seed(42) # 保证随机性可复现
                        portfolio_daily_returns = benchmark_daily_returns + np.random.normal(0.0003, 0.005, selected_days)
                        cumulative_returns = (1 + portfolio_daily_returns).cumprod() - 1

                        # 使用实际日期
                        dates = recent_benchmark['date'].dt.strftime("%Y-%m-%d").tolist()
                        # 确保日期列表长度与收益率数据一致
                        if len(dates) < selected_days:
                             # 如果日期不足，可能需要调整 selected_days 或填充日期，这里选择截断收益率数据
                             cumulative_returns = cumulative_returns[-len(dates):]
                             benchmark_cumulative_returns = benchmark_cumulative_returns[-len(dates):]
                        elif len(dates) > selected_days:
                             dates = dates[-selected_days:]


                    else: raise ValueError("有效基准价格数据不足")
                else: raise ValueError("基准数据时间序列不足")
            else: raise ValueError("无可用基准数据 (沪深300 或 上证指数)")
        else: raise ValueError("初始数据未加载")

    except Exception as e:
        logger.warning(f"创建收益曲线数据时出错，将使用随机数据: {e}")
        np.random.seed(42)
        portfolio_daily_returns = np.random.normal(0.0008, 0.012, selected_days)
        cumulative_returns = (1 + portfolio_daily_returns).cumprod() - 1
        benchmark_daily_returns = np.random.normal(0.0005, 0.010, selected_days)
        benchmark_cumulative_returns = (1 + benchmark_daily_returns).cumprod() - 1
        dates = pd.date_range(end=datetime.datetime.now(), periods=selected_days).strftime("%Y-%m-%d").tolist()
        benchmark_name = "模拟基准" # 如果使用随机数据，更改名称

    # 创建图表
    try:
        fig = go.Figure()
        fig.add_trace(go.Scatter(x=dates, y=cumulative_returns * 100, mode='lines', name='组合收益率', line=dict(color='#1E88E5', width=2)))
        fig.add_trace(go.Scatter(x=dates, y=benchmark_cumulative_returns * 100, mode='lines', name=f'基准收益率({benchmark_name})', line=dict(color='#FFC107', width=2, dash='dash')))
        fig.update_layout(
            title='收益率走势对比', xaxis_title='日期', yaxis_title='累计收益率(%)',
            legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
            height=400, margin=dict(t=50, l=10, r=10, b=10)
        )
        st.plotly_chart(fig, use_container_width=True)
    except Exception as e:
        logger.error(f"渲染收益曲线图时出错: {e}", exc_info=True)
        st.warning("无法渲染收益曲线图。")


def render_kpis():
    """渲染关键绩效指标"""
    st.markdown('<div class="sub-header">关键绩效指标</div>', unsafe_allow_html=True)
    # 这些指标通常需要基于历史收益数据计算，这里使用静态值
    # TODO: 基于收益曲线数据动态计算这些指标
    col1, col2, col3, col4 = st.columns(4)
    with col1: st.metric(label="年化收益率", value="18.5%", delta="+10.2%", help="相对基准的超额收益")
    with col2: st.metric(label="夏普比率", value="1.68", delta="+0.45", help="反映风险调整后收益水平")
    with col3: st.metric(label="最大回撤", value="12.3%", delta="-3.5%", help="相对基准的回撤对比")
    with col4: st.metric(label="信息比率", value="1.25", help="反映获取超额收益的能力")


def render_monthly_returns():
    """渲染月度收益表现热力图"""
    st.markdown('<div class="sub-header">月度收益表现</div>', unsafe_allow_html=True)
    monthly_returns = {}
    years = []

    # 尝试使用真实数据计算月度收益
    try:
        if st.session_state.get('data_loaded', False) and 'indices_data' in st.session_state:
            # 优先使用沪深300，其次上证指数作为基准
            benchmark_data = st.session_state.indices_data.get("沪深300")
            if benchmark_data is None or benchmark_data.empty:
                benchmark_data = st.session_state.indices_data.get("上证指数")

            if benchmark_data is not None and not benchmark_data.empty:
                # 确保日期列是 datetime 类型
                if not pd.api.types.is_datetime64_any_dtype(benchmark_data['date']):
                    benchmark_data['date'] = pd.to_datetime(benchmark_data['date'])

                benchmark_data = benchmark_data.sort_values(by="date").set_index('date')
                # 模拟组合月度收益 = 指数月度收益 + 随机调整
                monthly_data = benchmark_data['close'].resample('M').last() # 获取每月最后一天收盘价
                # 计算月度收益率
                monthly_pct_change = monthly_data.pct_change().dropna() # 删除第一个 NaN 值
                # 模拟组合超额收益
                np.random.seed(43) # 使用不同的种子
                portfolio_monthly_pct_change = monthly_pct_change + np.random.normal(0.005, 0.01, len(monthly_pct_change))
                portfolio_monthly_pct_change *= 100 # 转为百分比

                available_years = sorted(list(set(portfolio_monthly_pct_change.index.year)))
                years = available_years[-3:] # 最近3年

                for year in years:
                    year_data = portfolio_monthly_pct_change[portfolio_monthly_pct_change.index.year == year]
                    monthly_values = []
                    for month in range(1, 13):
                        month_dt = pd.Timestamp(year=year, month=month, day=1)
                        # 获取对应月份的数据，如果不存在则为 NaN
                        month_val = year_data[year_data.index.month == month].iloc[0] if month in year_data.index.month else np.nan
                        # 只显示已过去的月份 (或当月)
                        current_time = datetime.datetime.now()
                        if year < current_time.year or (year == current_time.year and month <= current_time.month):
                             monthly_values.append(month_val if pd.notna(month_val) else 0.0) # 用 0 填充 NaN
                        else:
                             monthly_values.append(None) # 未来月份为 None
                    monthly_returns[str(year)] = monthly_values
            else: raise ValueError("无可用基准数据 (沪深300 或 上证指数)")
        else: raise ValueError("初始数据未加载")

    except Exception as e:
        logger.warning(f"创建月度收益数据时出错，将使用默认数据: {e}")
        monthly_returns = {
            "2025": [2.8, 1.5, -0.8, 0.9, None, None, None, None, None, None, None, None],
            "2024": [1.5, -2.3, 3.2, 2.5, 1.8, -1.2, 3.5, 2.2, -0.5, 1.8, 2.5, 1.2],
            "2023": [3.2, 2.1, -1.5, -2.2, 1.5, 3.8, 2.5, -0.8, 1.2, 2.5, 3.2, 1.5]
        }
        years = list(monthly_returns.keys())

    # 创建热力图数据
    months_labels = [f"{i}月" for i in range(1, 13)]
    heatmap_data = []
    for year in years:
        if year in monthly_returns:
            for i, month_label in enumerate(months_labels):
                if i < len(monthly_returns[year]) and monthly_returns[year][i] is not None:
                    heatmap_data.append({"年份": year, "月份": month_label, "收益率": monthly_returns[year][i]})

    if not heatmap_data:
        st.info("无可用月度收益数据。")
        return

    heatmap_df = pd.DataFrame(heatmap_data)

    try:
        # 创建透视表，确保月份按正确顺序排列
        pivot_df = heatmap_df.pivot(index="年份", columns="月份", values="收益率")
        pivot_df = pivot_df.reindex(columns=months_labels) # 按月份排序

        fig = px.imshow(
            pivot_df,
            x=months_labels, y=pivot_df.index,
            color_continuous_scale='RdBu_r', # 红涨绿跌的反向色阶
            color_continuous_midpoint=0,
            aspect="auto",
            text_auto=True, # 启用自动文本标签
            labels=dict(x="月份", y="年份", color="收益率(%)")
        )
        fig.update_traces(
            hovertemplate="年份: %{y}<br>月份: %{x}<br>收益率: %{z:.1f}%<extra></extra>",
            texttemplate="%{z:.1f}" # 设置文本显示格式
        )
        fig.update_layout(height=max(200, len(years) * 50), margin=dict(t=30, l=10, r=10, b=10)) # 动态调整高度
        fig.update_coloraxes(colorbar_title_side='right')

        # 更新文本颜色以提高可读性
        fig.update_traces(textfont_color='white', selector=dict(type='heatmap'))
        # 对于接近0的值，可能需要黑色字体，但这比较复杂，暂时省略

        st.plotly_chart(fig, use_container_width=True)

    except Exception as e:
        logger.error(f"渲染月度收益热力图时出错: {e}", exc_info=True)
        st.warning("无法渲染月度收益热力图。")


def render_attribution_analysis():
    """渲染归因分析图 (行业和风格)"""
    st.markdown('<div class="sub-header">归因分析</div>', unsafe_allow_html=True)
    # 归因分析通常需要复杂的计算 (如 Brinson 模型)，这里使用静态/默认值
    sector_attribution = DEFAULT_SECTOR_ATTRIBUTION
    style_attribution = DEFAULT_STYLE_ATTRIBUTION

    # 尝试从 workflow_result 获取归因数据 (如果存在)
    # if st.session_state.get('workflow_result') ...

    col1, col2 = st.columns(2)
    with col1:
        st.markdown("#### 行业归因")
        try:
            colors = ['#1E88E5' if v > 0 else '#FF5252' for v in sector_attribution.values()]
            fig = go.Figure(data=[go.Bar(x=list(sector_attribution.keys()), y=list(sector_attribution.values()), marker_color=colors)])
            fig.update_layout(title='行业贡献(%)', yaxis_title='收益贡献(%)', height=300, margin=dict(t=40, l=10, r=10, b=10))
            st.plotly_chart(fig, use_container_width=True)
        except Exception as e:
            logger.error(f"渲染行业归因图时出错: {e}", exc_info=True)
            st.warning("无法渲染行业归因图。")

    with col2:
        st.markdown("#### 风格归因")
        try:
            colors = ['#1E88E5' if v > 0 else '#FF5252' for v in style_attribution.values()]
            fig = go.Figure(data=[go.Bar(x=list(style_attribution.keys()), y=list(style_attribution.values()), marker_color=colors)])
            fig.update_layout(title='风格贡献(%)', yaxis_title='收益贡献(%)', height=300, margin=dict(t=40, l=10, r=10, b=10))
            st.plotly_chart(fig, use_container_width=True)
        except Exception as e:
            logger.error(f"渲染风格归因图时出错: {e}", exc_info=True)
            st.warning("无法渲染风格归因图。")


def render_risk_analysis():
    """渲染风险分析部分"""
    st.markdown('<div class="sub-header">风险分析</div>', unsafe_allow_html=True)
    # 风险分析同样需要基于历史数据计算，这里使用静态/默认值
    risk_breakdown = DEFAULT_RISK_BREAKDOWN
    risk_metrics = DEFAULT_RISK_METRICS

    col1, col2 = st.columns(2)
    with col1:
        st.markdown("#### 风险分解")
        try:
            fig = px.pie(
                names=list(risk_breakdown.keys()), values=list(risk_breakdown.values()),
                hole=0.4, color_discrete_sequence=px.colors.sequential.Reds
            )
            fig.update_traces(textposition='inside', textinfo='percent+label')
            fig.update_layout(height=300, margin=dict(t=30, l=10, r=10, b=10), showlegend=False)
            st.plotly_chart(fig, use_container_width=True)
        except Exception as e:
            logger.error(f"渲染风险分解图时出错: {e}", exc_info=True)
            st.warning("无法渲染风险分解图。")

    with col2:
        st.markdown("#### 风险指标")
        try:
            metrics_df = pd.DataFrame(risk_metrics.items(), columns=["指标", "数值"])
            st.dataframe(
                metrics_df,
                column_config={
                    "指标": st.column_config.TextColumn("风险指标", width="medium"),
                    "数值": st.column_config.NumberColumn("数值", format="%.2f", width="small"),
                },
                hide_index=True, use_container_width=True
            )
            with st.expander("指标说明"):
                st.markdown("""
                - **波动率**: 反映收益率的波动程度，数值越大表示波动越大
                - **Beta系数**: 相对于市场基准的波动幅度，大于1表示波动大于市场
                - **下行风险**: 只考虑亏损部分的波动程度
                - **跟踪误差**: 相对于基准的偏离程度
                - **VaR(95%)**: 在95%置信区间下的最大可能损失
                - **信息比率**: 超额收益与跟踪误差之比，反映获取超额收益的效率
                """)
        except Exception as e:
            logger.error(f"渲染风险指标时出错: {e}", exc_info=True)
            st.warning("无法渲染风险指标。")